#ifndef SCDIRWATCHER_H
#define SCDIRWATCHER_H

/**
 * Desc: SCDirWatcher 文件夹行为监控。仅支持 * linux2.6.13以后的内核 * windows 和 
 * MAC ox10.5以上的系统。不同平台对于重命名的处理是不同的。
 *	linux ->对监控的多个文件夹中的文件相互移动作为单一移动操作(inotify)
 *	windows ->对监控的多个文件夹中的文件相互移动作为"源头删除，目标新建"
 *	两个操作。不支持文件和文件夹分类的监听(ReadDirectoryW)
 *	mac ->TODO:我还不知道(FSEvent)
 * Auth: 张宇飞
 * Date: 2015-03-13    
 */

#include <vector>
#include <string>
#include <map>
#include <set>

// 定义平台宏
#if defined(__linux__) || defined(__linux)
#define OS_LINUX
#include <sys/inotify.h>
#define SC_IHANDLE		int
#define SC_INVALID_HANDLE_VALUE	-1
#define SC_SEPERATOR_CHAR	'/'
#elif defined(__APPLE__)
#define OS_MAC
#define SC_IHANDLE		int
#define SC_INVALID_HANDLE_VALUE	-1
#define SC_SEPERATOR_CHAR	'/'

#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ||  defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
#define OS_WIN
#include <windows.h>
#define SC_IHANDLE		HANDLE
#define SC_INVALID_HANDLE_VALUE	INVALID_HANDLE_VALUE
#define SC_SEPERATOR_CHAR	'\\'
#endif

// 两组map的方便宏
#define SC_DIR_PAIR	const SC_IHANDLE,SCDirWatcher::DirInfo_t*
#define SC_DIR_MAP	std::map<SC_DIR_PAIR>
#define SC_DESC_PAIR	const std::string,SC_DIR_MAP::iterator
#define SC_DESC_MAP	std::map<SC_DESC_PAIR>

class SCDirWatcher
{
public:
	struct DirInfo_t;	//用来存放必要信息的私有结构
	enum {
		New = 0x1,	// 被追踪目录出现了新的文件/文件夹
		Del = 0x2,	// 被追踪目录中消失了一个文件或者文件夹
		Mod = 0x4,	// 被追踪目录中的文件/文件夹被修改了
		RNa = 0x8,	// 被追踪目录中的文件/文件夹修改了名字
		Dir = 0x10	// 被追踪的目标是个文件夹
	};

	// 监控结果
	struct FState {
		void		zero() {
			oldName.clear();
			newName.clear();
			flag = 0;
		}

		int		flag;
		std::string	oldName;
		std::string	newName;
	};

	// 监控通知接口
	class WatcherProto
	{
		friend class SCDirWatcher;
	protected:
		virtual void	onFileWatch(const SCDirWatcher::FState& s) = 0;
#ifndef OS_WIN
		virtual void	onDirWatch(const SCDirWatcher::FState& s) = 0;
#endif
		virtual void	onWatchLose(const std::string& path) = 0;
	};

public:
	explicit SCDirWatcher(SCDirWatcher::WatcherProto* pproto = NULL);
	~SCDirWatcher();
public:
	void			updateOnce();
	bool 			add(std::string path);
	bool 			remove(std::string path);
	/* 获取被监视的文件/文件 */
	bool 			dirs(std::vector<std::string>& out);
private:
#ifdef OS_LINUX
	void 			getFileFullName(const inotify_event* pe, FState& st, bool newOrOld);
	bool normalFStateCheck(SCDirWatcher::FState& st,  const inotify_event* pe);
	bool 			tryAddFState(std::vector<SCDirWatcher::FState>& vec,
					const inotify_event* pe, const inotify_event* pl, bool endCheck);
#elif defined(__APPLE__)
	// TODO:
#else
	void			getFileFullName(const std::string& dpath, const wchar_t* name, 
					DWORD namel, std::string& out);
	void			initFStateFromDirInfo(DirInfo_t* pinfo);
#endif
private:
	WatcherProto*		m_proto;
	SC_IHANDLE		m_ihandle;
	SC_DIR_MAP		m_dirMap;
 	SC_DESC_MAP		m_descMap;
};

#endif // SCDIRWATCHER_H
